using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using MacomberMapSystem.Common.CIM;
using MacomberMapSystem.Common.Database;
using System.Data.SQLite;
using System.Threading;

namespace MacomberMapSystem.Common.User_Interfaces.CIM_Browser
{
    /// <summary>
    /// This class allows for selection of a CIM element
    /// </summary>
    public partial class CIM_Element_Locator : UserControl
    {
        #region Event handling
        /// <summary>
        /// Indicate that an element has been selected
        /// </summary>
        /// <param name="SelectedElement">The selected element</param>
        /// <param name="ParentElement">The parent element calling for the new element</param>
        public delegate void ElementSelectedDelegate(CIM_Element SelectedElement, CIM_Element_FrontEnd ParentElement);

        /// <summary>
        /// An element has been selected
        /// </summary>
        public event ElementSelectedDelegate ElementSelected;

        /// <summary>The CIM connector associated with this view</summary>
        public MM_Database_Model CIM;
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize the CIM locator
        /// </summary>        
        public CIM_Element_Locator()
        {
            try
            {
                InitializeComponent();
               
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message + "\n\n" + ex.StackTrace, Application.ProductName,  MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Assign our CIM connector for the specified locator
        /// </summary>
        /// <param name="CIM"></param>
        public void AssignConnector(MM_Database_Model CIM)
        {
            this.CIM = CIM;
            cmbElementType.Items.Clear();
            cmbSubstations.Items.Clear();
            cmbContingencies.Items.Clear();


            cmbElementType.Items.AddRange(CIM.Types.ToArray());
            foreach (String Sub in CIM.Substations.Keys)
                cmbSubstations.Items.Add(Sub);
            foreach (String Ctg in CIM.Traces.Keys)
                cmbContingencies.Items.Add(Ctg);            
            cmbElementType.Sorted = true;            
        }
        #endregion

        #region User interactions       
        /// <summary>
        /// When the type changes, update accordingly.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateRDFByIndex(object sender, EventArgs e)
        {
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");            
            foreach (CIM_Element Elem in CIM.ElementsOfType(cmbElementType.Text))
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name)].Tag = Elem;

        }

        /// <summary>
        /// Locate the requested rdf:ID
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtRdfID_TextChanged(object sender, EventArgs e)       
        {
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");

            CIM_Element Elem = CIM.FromRdfID(txtRdfID.Text);
            if (Elem != null)
                dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name)].Tag = Elem;
        }

        /// <summary>
        /// Loacate the requested TEID
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtTEID_TextChanged(object sender, EventArgs e)
        {

            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");

            
            
            UInt64 TEID;            
            if (UInt64.TryParse(txtTEID.Text, out TEID))
            {
                CIM_Element FoundElem = CIM.FromTEID(TEID);
               if (FoundElem != null)
                   dgvElements.Rows[dgvElements.Rows.Add(FoundElem.rdfID.ToString(), FoundElem.Name)].Tag = FoundElem;
            }
        }

        /// <summary>
        /// Update only elements within the selected substation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbSubstations_SelectedIndexChanged(object sender, EventArgs e)
        {

            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");
            dgvElements.Columns.Add("Type", "Type");
            dgvElements.Columns.Add("TEID", "TEID");
            if (cmbSubstations.SelectedItem == null)
                return;


            CIM_Element Sub;
            if (CIM.Substations.TryGetValue((string)cmbSubstations.SelectedItem, out Sub))                                   
                foreach (CIM_Element Elem in Sub.Elements)
                    dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name, Elem.TypeName.Split(':')[1], Elem.TEID)].Tag = Elem;
            

            //foreach (CIM_Element Elem in Subs[(string)cmbSubstations.SelectedItem].Nodes)
            //    dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name, Elem.Type.Split(':')[1], Elem.TEID)].Tag = Elem;
        }

        /// <summary>
        /// Update only elements within the selected contingency definition
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbContingencies_SelectedIndexChanged(object sender, EventArgs e)
        {
            dgvElements.Rows.Clear();
            dgvElements.Columns.Clear();
            dgvElements.Columns.Add("rdfID", "rdf:ID");
            dgvElements.Columns.Add("Name", "Name");
            dgvElements.Columns.Add("Type", "Type");
            dgvElements.Columns.Add("TEID", "TEID");
            if (cmbContingencies.SelectedItem == null)
                return;

            CIM_Trace Ctg;
            if (CIM.Traces.TryGetValue((string)cmbContingencies.SelectedItem, out Ctg))
                foreach (CIM_Element Elem in Ctg.Elements)
                    dgvElements.Rows[dgvElements.Rows.Add(Elem.rdfID.ToString(), Elem.Name, Elem.TypeName.Split(':')[1], Elem.TEID)].Tag = Elem;          
        }


        /// <summary>
        /// Add an attribute in to the data grid view
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OutItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {            

            String AttributeType = e.ClickedItem.Tag as string;
            int NewColNum = dgvElements.Columns.Add(AttributeType,AttributeType.Substring(AttributeType.LastIndexOf('.')+1));
            DataGridViewColumn NewCol = dgvElements.Columns[NewColNum];                
            NewCol.ToolTipText = AttributeType;
            ThreadPool.QueueUserWorkItem(AddRowItems, new object[] { dgvElements.Rows, AttributeType});
            (sender as ToolStripDropDownItem).Owner.Hide();                            
        }


        /// <summary>
        /// Add items to our display
        /// </summary>
        /// <param name="state"></param>
        private void AddRowItems(Object state)
        {
            DataGridViewRowCollection dgvrc = ((object[])state)[0] as DataGridViewRowCollection;
            String AttributeType = ((object[])state)[1].ToString();
            foreach (DataGridViewRow dgr in dgvrc)
                if (dgr.Tag is CIM_Element)
                {
                    dgr.Cells[AttributeType].Value = MacomberMapSystem.Common.Internals.MM_Type_Converter.TitleCase((dgr.Tag as CIM_Element)[AttributeType]);
                    if (dgr.Index % 100 == 0)
                        Application.DoEvents();
                }
        }



        /// <summary>
        /// Handle the user's double clicking by returning the selected element
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (ElementSelected != null && e.RowIndex > -1)
                ElementSelected(dgvElements.Rows[e.RowIndex].Tag as CIM_Element,null);
        }

        /// <summary>
        /// Handle the right-click on the elements view, allowing for different types to be added in.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_MouseClick(object sender, MouseEventArgs e)
        {
            //If we have a right-click button, pop up a menu of all possible attribute types
            if (e.Button == MouseButtons.Right)
            {
                List<Byte> SeenTypes = new List<byte>();
                SortedDictionary<String, bool> Attributes = new SortedDictionary<string, bool>();                
                foreach (DataGridViewRow dgr in dgvElements.Rows)
                    if (dgr.Tag is CIM_Element && !SeenTypes.Contains((dgr.Tag as CIM_Element).Type))
                    {
                        foreach (int Attr in CIM.AttributesByType[(dgr.Tag as CIM_Element).Type])
                            if (!Attributes.ContainsKey(CIM.Attributes[Attr]))
                                Attributes.Add(CIM.Attributes[Attr], true);
                        SeenTypes.Add((dgr.Tag as CIM_Element).Type);
                    }

                //Now, build out our menu
                ContextMenuStrip cms = new ContextMenuStrip();
                foreach (String str in Attributes.Keys)
                {
                    String[] splStr = str.Split(new char[] { '.' }, 2);
                    ToolStripMenuItem OutItem;
                    if (cms.Items.ContainsKey(splStr[0]))
                        OutItem = cms.Items[splStr[0]] as ToolStripMenuItem;
                    else
                    {
                        OutItem = cms.Items.Add(splStr[0]) as ToolStripMenuItem;
                        OutItem.Name = splStr[0];
                        OutItem.DropDownItemClicked += new ToolStripItemClickedEventHandler(OutItem_DropDownItemClicked);
                    }
                    if (splStr.Length == 1)
                        splStr = new string[] { splStr[0], splStr[0] };
                    (OutItem.DropDownItems.Add(splStr[1]) as ToolStripItem).Tag = str;
                }

                ToolStripMenuItem Sub = cms.Items.Add("Substation") as ToolStripMenuItem;
                Sub.Name = "Substation";
                Sub.DropDownItemClicked += new ToolStripItemClickedEventHandler(OutItem_DropDownItemClicked);
                Sub.DropDownItems.Add("Name").Tag = "Substation>Name";
                Sub.DropDownItems.Add("LongName").Tag = "Substation>LongName";
                Sub.DropDownItems.Add("Owner").Tag = ">Substation>Owner>Name";
                ToolStripMenuItem ElemType = cms.Items.Add("Properties") as ToolStripMenuItem;
                ElemType.Name = "Properties";
                ElemType.DropDownItemClicked += new ToolStripItemClickedEventHandler(OutItem_DropDownItemClicked);
                foreach (System.Reflection.PropertyInfo pI in typeof(CIM_Element).GetProperties())
                    if (pI.PropertyType == typeof(string) || pI.PropertyType == typeof(CIM_Element) || pI.PropertyType == typeof(CIM_Element[]))
                        ElemType.DropDownItems.Add(pI.Name).Tag = pI.Name;
                ElemType.DropDown.Items.Add("Operator alias").Tag = ">Operatorship>Company>aliasName";
                ElemType.DropDown.Items.Add("Owner alias").Tag = ">Ownership>Company>aliasName";
                
                cms.Show(sender as Control, e.Location);

            }
        }
        #endregion

        #region Drag/drop handling
        /// <summary>
        /// Allow the user to drag/drop a CIM element out of the window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && dgvElements.SelectedCells.Count > 0 && !dgvElements.Bounds.Contains(e.Location))
            {
                Dictionary<CIM_Element, bool> SelectedElements = new Dictionary<CIM_Element, bool>();
                foreach (DataGridViewCell dgvc in dgvElements.SelectedCells)
                    if (!SelectedElements.ContainsKey(dgvElements.Rows[dgvc.RowIndex].Tag as CIM_Element))
                        SelectedElements.Add(dgvElements.Rows[dgvc.RowIndex].Tag as CIM_Element, true);
                CIM_Element[] SelectedDrop = new CIM_Element[SelectedElements.Count];
                SelectedElements.Keys.CopyTo(SelectedDrop, 0);
                dgvElements.DoDragDrop(SelectedDrop, DragDropEffects.All);
            }
        }

        /// <summary>
        /// Update our list of selected elements for potential drag/drop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvElements_SelectionChanged(object sender, EventArgs e)
        {
            
        }
        #endregion


       






    }
}
